//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CEffectVariable9.cpp>
///	@path	~/src/graphics/dx9/
///	@date	2007/11/20
///	@desc	Shader variable dx 9.

#include "config/config.h"

#include "lib/utilities/debug.h"
#include "lib/system/thread_debug.h"

#include "graphics/DxHelpers.h"
#include "graphics/IRenderTarget.h"
#include "graphics/dx9/CTexture2D9.h"
#include "graphics/dx9/CEffectVariable9.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CEffectVariable9 );

	// ctor
	CEffectVariable9::CEffectVariable9( RefWeak<CEffect9> effect , D3DXHANDLE param )
		: m_effect( effect )
		, m_pParam( param )
	{
		memset( &m_desc , 0 , sizeof(D3DXPARAMETER_DESC) );
		HRESULT hr = (*effect)->GetParameterDesc( param , &m_desc );
		XS_ASSERT( SUCCEEDED(hr) );
	}

	// dtor
	CEffectVariable9::~CEffectVariable9( void )
	{
		if( m_effect.IsValid() )
		{
			m_effect->UnusedVariable( this );
		}
	}

	RefPass< IObject > CEffectVariable9::GetMaster( void )
	{
		return m_effect;
	}

	bool CEffectVariable9::SetByVar( RefWeak< IVar > var )
	{
		//
		return false;
	}

	// SetByData
	bool CEffectVariable9::SetByData( const void * data , size_t bytes )
	{
		if( bytes > m_desc.Bytes )
		{
			TRACE_ERROR( _S("CEffectVariable9::SetByData: Data size does not match.") );
			return false;
		}
		HRESULT hr = m_effect->GetEffect()->SetValue( m_pParam , data , bytes );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable9::SetByData: Failed to set variable: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}

	// SetByTexture
	bool CEffectVariable9::SetByTexture( RefWeak<ITexture> texture )
	{
		IDirect3DTexture9 * handle = NULL;
		if( texture.IsValid() )
		{
			texture->GetTextureInterface()->QueryInterface( IID_IDirect3DTexture9 , (void**)&handle );
		}
		HRESULT hr = m_effect->GetEffect()->SetTexture( m_pParam , handle );
		if( handle )
			handle->Release();
		handle = NULL;
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable9::SetByTexture: Failed to set texture: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}
	// SetByRenderTarget
	bool CEffectVariable9::SetByRenderTarget( RefWeak< IRenderTarget > rt )
	{
		IDirect3DTexture9 * handle = NULL;
		if( rt.IsValid() )
		{
			rt->GetTextureInterface()->QueryInterface( IID_IDirect3DTexture9 , (void**)&handle );
		}
		HRESULT hr = m_effect->GetEffect()->SetTexture( m_pParam , handle );
		if( handle )
			handle->Release();
		handle = NULL;
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable9::SetByRenderTarget: Failed to set render target: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}
	// GetVarTypeName
	const WString& CEffectVariable9::GetVarTypeName( void ) const
	{
		static const WString s_defaultName( _S("") );
		return s_defaultName;
	}
	// GetVarTypeID
	const ClassID CEffectVariable9::GetVarTypeID( void ) const
	{
		switch( m_desc.Type )
		{
		case D3DXPT_BOOL:
			if( m_desc.Class == D3DXPC_SCALAR )
				return BOOL_TYPE_CLASS_ID;
			break;
		case D3DXPT_INT:
			if( m_desc.Class == D3DXPC_SCALAR )
				return INT_TYPE_CLASS_ID;
			break;
		case D3DXPT_FLOAT:
			if( m_desc.Class == D3DXPC_SCALAR )
				return FLOAT_TYPE_CLASS_ID;
			if( m_desc.Type == D3DXPC_VECTOR ) {
				if( m_desc.Elements == 3 )
					return VECTOR_TYPE_CLASS_ID;
				else if( m_desc.Elements == 4 )
					return COLOR_TYPE_CLASS_ID;
			} else if( m_desc.Class == D3DXPC_MATRIX_ROWS ) {
				return MATRIX_TYPE_CLASS_ID;
			}
			break;
		case D3DXPT_STRING:
			if( m_desc.Class == D3DXPC_SCALAR )
				return STRING_TYPE_CLASS_ID;
			break;
		}
		return VOID_TYPE_CLASS_ID;
	}
	// DuplicateFrom
	bool CEffectVariable9::DuplicateFrom( const Ref<IVar>& val )
	{
		return false;
	}
	// SetBool
	bool CEffectVariable9::SetBool( bool val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetBool( m_pParam , val ) );
	}
	// SetInt
	bool CEffectVariable9::SetInt( int val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetInt( m_pParam , val ) );
	}
	// SetFloat
	bool CEffectVariable9::SetFloat( float val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetFloat( m_pParam , val ) );
	}
	// SetPair
	bool CEffectVariable9::SetPair( const Pair<float>& val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetFloatArray( m_pParam , val.f , 2 ) );
	}
	// SetVector
	bool CEffectVariable9::SetVector( const Vector<float>& val )
	{
		D3DXVECTOR4 vec( val.x , val.y , val.z , 1 );
		return SUCCEEDED( m_effect->GetEffect()->SetVector( m_pParam , &vec ) );
	}
	// SetQuat
	bool CEffectVariable9::SetQuat( const Quat<float>& val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetFloatArray( m_pParam , val.f , 4 ) );
	}
	// SetColor
	bool CEffectVariable9::SetColor( const Color4& val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetFloatArray( m_pParam , val.c , 2 ) );
	}
	// SetMatrix
	bool CEffectVariable9::SetMatrix( const Matrix<float>& val )
	{
		return SUCCEEDED( m_effect->GetEffect()->SetMatrix( m_pParam , (D3DXMATRIX*)val.m16 ) );
	}
	// SetString
	bool CEffectVariable9::SetString( const WString& val )
	{
		AString buf;
		wcs_to_mbs( val , buf );
		return SUCCEEDED( m_effect->GetEffect()->SetString( m_pParam , buf.c_str() ) );
	}
	// SetObject
	bool CEffectVariable9::SetObject( RefWeak<IObject> val )
	{
		if( val->IsA<ITexture>() )
		{
			if( val->IsA<IRenderTarget>() )
			{
				return SetByRenderTarget( RefWeak<IRenderTarget>(val) );
			}
			return SetByTexture( RefWeak<ITexture>(val) );
		}
		return false;
	}
	// GetBool
	bool CEffectVariable9::GetBool( bool& val ) const
	{
		BOOL proxy;
		HRESULT hr = m_effect->GetEffect()->GetBool( m_pParam , &proxy );
		if( SUCCEEDED(hr) )
		{
			val = proxy ? true : false;
			return true;
		}
		return false;
	}
	// GetInt
	bool CEffectVariable9::GetInt( int& val ) const
	{
		return SUCCEEDED( m_effect->GetEffect()->GetInt( m_pParam, &val ) );
	}
	// GetFloat
	bool CEffectVariable9::GetFloat( float& val ) const
	{
		return SUCCEEDED( m_effect->GetEffect()->GetFloat( m_pParam, &val ) );
	}
	// GetPair
	bool CEffectVariable9::GetPair( Pair<float>& val ) const
	{
		FLOAT ff[2];
		HRESULT hr = m_effect->GetEffect()->GetFloatArray( m_pParam , ff , 2 );
		if( SUCCEEDED(hr) )
		{
			val.copy( ff );
			return true;
		}
		return false;
	}
	// GetVector
	bool CEffectVariable9::GetVector( Vector<float>& val ) const
	{
		D3DXVECTOR4 v;
		HRESULT hr = m_effect->GetEffect()->GetVector( m_pParam , &v );
		if( SUCCEEDED(hr) )
		{
			val.copy( (float*)&v );
			return true;
		}
		return false;
	}
	// GetQuat
	bool CEffectVariable9::GetQuat( Quat<float>& val ) const
	{
		FLOAT ff[4];
		HRESULT hr = m_effect->GetEffect()->GetFloatArray( m_pParam , ff , 4 );
		if( SUCCEEDED(hr) )
		{
			val.copy( ff );
			return true;
		}
		return false;
	}
	// GetColor
	bool CEffectVariable9::GetColor( Color4& val ) const
	{
		FLOAT ff[4];
		HRESULT hr = m_effect->GetEffect()->GetFloatArray( m_pParam , ff , 4 );
		if( SUCCEEDED(hr) )
		{
			val.copy( ff );
			return true;
		}
		return false;
	}
	// GetMatrix
	bool CEffectVariable9::GetMatrix( Matrix<float>& val ) const
	{
		D3DXMATRIX mat;
		HRESULT hr = m_effect->GetEffect()->GetMatrix( m_pParam , &mat );
		if( SUCCEEDED(hr) )
		{
			val.copy( (float*)&mat );
			return true;
		}
		return false;
	}
	// GetString
	bool CEffectVariable9::GetString( WString& val ) const
	{
		LPCSTR pStr = NULL;
		HRESULT hr = m_effect->GetEffect()->GetString( m_pParam , &pStr );
		if( SUCCEEDED(hr) )
		{
			mbs_to_wcs( pStr , val );
			return true;
		}
		return false;
	}
	// GetObject
	bool CEffectVariable9::GetObject( Ref<IObject>& val ) const
	{
		return false;
	}

} // namespace xeres
